#include <string>
#include <vector>
#include <stdlib.h>
#include "log.h"
#include "redis.h"

using namespace std;

Redis::Redis()
{
}

Redis::~Redis()
{
    release();
}

void Redis::release()
{
    map<IpPort,redisContext*>::iterator itConn;
    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
            redisFree(itConn->second);
    }
    m_conns.clear();
}

void Redis::SetServer(const string &ip, unsigned int port) 
{
    m_conns[IpPort(ip,port)] = NULL;
}

void Redis::Reconnect()
{
    map<IpPort,redisContext*>::iterator itConn;
    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
        {
            DBG_LOG("connecting to %s:%u.",itConn->first.m_ip.c_str(),itConn->first.m_port);
            itConn->second = redisConnect(itConn->first.m_ip.c_str(), itConn->first.m_port);
        }
        else if (itConn->second->err != 0)
        {
            redisFree(itConn->second);
            DBG_LOG("connecting to %s:%u.",itConn->first.m_ip.c_str(),itConn->first.m_port);
            itConn->second = redisConnect(itConn->first.m_ip.c_str(), itConn->first.m_port);
        }
    }
}

void Redis::SetKeyValue(const string& key, const string &value, const string &ttl) {
    
    Reconnect();
    
    redisReply* rsp = NULL;
    map<IpPort,redisContext*>::iterator itConn;
    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
            continue;
        rsp = (redisReply*)redisCommand(itConn->second, "SET %b %b EX %s",
                key.c_str(), key.size(), value.c_str(), value.size(), ttl.c_str());
        // m_ctx->err 检测连接中断 或者 server 挂掉
        if (itConn->second->err != 0)
        {
            if (rsp != NULL)
            {
                freeReplyObject(rsp);
            }
            continue;
        }
        
        if (rsp != NULL)
            freeReplyObject(rsp);
        
        break;
    }
}

void Redis::HSetKeyValue(const string& hash, const string& key, const string &value, const string &ttl) {
    
    Reconnect();

    redisReply* rsp = NULL;
    map<IpPort,redisContext*>::iterator itConn;
    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
            continue;
        rsp = (redisReply*)redisCommand(itConn->second, "HSET %b %b %b",
                hash.c_str(), hash.size(), key.c_str(), key.size(), value.c_str(), value.size());
        // m_ctx->err 检测连接中断 或者 server 挂掉
        if (itConn->second->err != 0)
        {
            if (rsp != NULL)
            {
                freeReplyObject(rsp);
            }
            continue;
        }
        
        if (rsp != NULL)
            freeReplyObject(rsp);
        rsp = (redisReply*)redisCommand(itConn->second, "EXPIRE %s %s",hash.c_str(),ttl.c_str() );
        if (rsp != NULL)
            freeReplyObject(rsp);
    
        break;
    }
}

string Redis::HGetKeyValue(const string& hash, const string& key) {
    Reconnect();
    
    redisReply* rsp = NULL;
    map<IpPort,redisContext*>::iterator itConn;
    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
            continue;
        rsp = (redisReply*)redisCommand(itConn->second, "HGET %b %b",
                hash.c_str(),
                hash.size(),
                key.c_str(),
                key.size());
	    
        // m_ctx->err 检测连接中断 或者 server 挂掉
        if (itConn->second->err != 0)
        {
            if (rsp != NULL)
            {
                freeReplyObject(rsp);
            }
            continue;
        }
        
        if (rsp != NULL)
        {
            if (rsp->type == REDIS_REPLY_STRING)
            {
                return rsp->str;
            }
            else if(rsp->type == REDIS_REPLY_ERROR)
            {
                ERR_LOG("redis error:%s.",rsp->str);
            }
            freeReplyObject(rsp);
        }
        
        break;
    }
    return "";
}

void Redis::Exec(const string& cmd)
{
    Reconnect();
    
    redisReply* rsp = NULL;
    map<IpPort,redisContext*>::iterator itConn;
    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
            continue;
        rsp = (redisReply*)redisCommand(itConn->second, cmd.c_str());
	    
        // m_ctx->err 检测连接中断 或者 server 挂掉
        if (itConn->second->err != 0)
        {
            if (rsp != NULL)
            {
                freeReplyObject(rsp);
            }
            continue;
        }

        if (rsp != NULL)
            freeReplyObject(rsp);

        break;
    }
}

string Redis::GetKey(const string& key)
{
    Reconnect();
    
    redisReply* rsp = NULL;
    map<IpPort,redisContext*>::iterator itConn;
    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
            continue;
        rsp = (redisReply*)redisCommand(itConn->second, "GET %b", key.c_str(), key.size());
        // m_ctx->err 检测连接中断 或者 server 挂掉
        if (itConn->second->err != 0)
        {
            if (rsp != NULL)
            {
                freeReplyObject(rsp);
            }
            continue;
        }

        if (rsp != NULL)
        {
            if (rsp->type == REDIS_REPLY_STRING)
            {
                return rsp->str;
            }
            else if(rsp->type == REDIS_REPLY_ERROR)
            {
                ERR_LOG("redis error:%s.",rsp->str);
            }
            freeReplyObject(rsp);
        }
    
        break;
    }

    return "";
}


long long Redis::GetInt(const string& key)
{
    Reconnect();

    long long result = 0;
    redisReply* rsp = NULL;
    map<IpPort,redisContext*>::iterator itConn;

    for (itConn = m_conns.begin(); itConn != m_conns.end(); ++itConn)
    {
        if (itConn->second == NULL)
            continue;
        rsp = (redisReply*)redisCommand(itConn->second,"GET %b", key.c_str(), key.size());
        
        if (itConn->second->err != 0)
        {
            if (rsp != NULL)
            {
                freeReplyObject(rsp);
            }
            continue;
        }

        if (rsp != NULL)
        {
            if (rsp->type == REDIS_REPLY_INTEGER)
            {
                result = rsp->integer;
            }
            else if (rsp->type == REDIS_REPLY_NIL)
            {
                result = 0;
            }

            if (rsp->type == REDIS_REPLY_STRING)
            {
                result = atoi(rsp->str);
            }
            else if(rsp->type == REDIS_REPLY_ERROR)
            {
                ERR_LOG("redis error:%s.",rsp->str);
            }
            freeReplyObject(rsp);
        }

        break;
    }
    return result;
}




